package com.satan.fmmall.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.wxpay.sdk.WXPay;
import com.satan.fmmall.config.MyPayConfig;
import com.satan.fmmall.entity.OrderItem;
import com.satan.fmmall.entity.Orders;
import com.satan.fmmall.entity.ProductSku;
import com.satan.fmmall.mapper.OrderItemMapper;
import com.satan.fmmall.mapper.OrdersMapper;
import com.satan.fmmall.mapper.ProductSkuMapper;
import com.satan.fmmall.mapper.ShoppingCartMapper;
import com.satan.fmmall.service.OrderService;
import com.satan.fmmall.vo.*;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @ClassName OrderServiceImpl
 * @Description TODO
 * @date 2022/4/17 14:15
 * @Version 1.0
 */
@Service
public class OrderServiceImpl implements OrderService {
    @Resource
    private ShoppingCartMapper shoppingCartMapper;
    @Resource
    private OrdersMapper ordersMapper;
    @Resource
    private OrderItemMapper orderItemMapper;
    @Resource
    private ProductSkuMapper productSkuMapper;
    @Resource
    private MyPayConfig myPayConfig;
    @Resource
    private RedisTemplate<String, String> redisTemplate;
    @Resource
    private RedissonClient redissonClient;

    @Override
    @Transactional
    public ResultVo addOrder(String cartIds, Orders orders) {
        synchronized (this) {
            String[] split = cartIds.split(",");
            List<Integer> list = new ArrayList<>();
            Arrays.stream(split).forEach(s -> list.add(Integer.parseInt(s)));
//        System.out.println("list = " + list);
            //根据购物车id查询购物车详情
            List<ShoppingCartVo> shoppingCartVoList = shoppingCartMapper.selectShopCartsByCartIds(list);
            //从购物车信息中获取到要购买的skuId,以skuId为key写道redis中
            Boolean isLocked = true;
            List<String> lockedList = new ArrayList<>();
            Map<String, RLock> lockMap = new HashMap<>();
            for (ShoppingCartVo shoppingCartVo : shoppingCartVoList) {
                String skuId = shoppingCartVo.getSkuId();
                RLock lock = redissonClient.getLock(skuId);
                boolean b = false;
                try {
                    b = lock.tryLock(10, 10, TimeUnit.SECONDS);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                if (b) {
                    lockedList.add(skuId);
                    lockMap.put(skuId, lock);
                }
                isLocked = isLocked && b;
            }
            try {
                if (isLocked) {
                    //防止并发对数据产生修改，再次进行查询操作
                    shoppingCartVoList = shoppingCartMapper.selectShopCartsByCartIds(list);
                    //校验库存
                    boolean f = true;
                    for (ShoppingCartVo shoppingCartVo : shoppingCartVoList) {
                        if (Integer.parseInt(shoppingCartVo.getCartNum()) > shoppingCartVo.getSkuStock()) {
                            f = false;
                            break;
                        }
                    }
                    if (f) {
                        String untitled = shoppingCartVoList.stream().map(ShoppingCartVo::getProductName).collect(Collectors.joining(","));
                        //System.out.println("untitled = " + untitled);
                        orders.setStatus("1");
                        orders.setUntitled(untitled);
                        //插入订单
                        int i = ordersMapper.insert(orders);
                        boolean flag = true;
                        if (i > 0) {
                            //生成商品快照
                            for (ShoppingCartVo shoppingCartVo : shoppingCartVoList) {
                                OrderItem orderItem = new OrderItem();
                                orderItem.setOrderId(orders.getOrderId());
                                orderItem.setProductId(shoppingCartVo.getProductId());
                                orderItem.setProductImg(shoppingCartVo.getProductImg());
                                orderItem.setProductName(shoppingCartVo.getProductName());
                                orderItem.setSkuId(shoppingCartVo.getSkuId());
                                orderItem.setSkuName(shoppingCartVo.getSkuName());
                                orderItem.setProductPrice(BigDecimal.valueOf(shoppingCartVo.getSellPrice()));
                                orderItem.setBuyCounts(Integer.valueOf(shoppingCartVo.getCartNum()));
                                orderItem.setTotalAmount(BigDecimal.valueOf(shoppingCartVo.getSellPrice() * Integer.parseInt(shoppingCartVo.getCartNum())));
                                orderItem.setIsComment(0);
                                int i1 = orderItemMapper.insert(orderItem);

                            }

                            //修改库存
                            for (ShoppingCartVo shoppingCartVo : shoppingCartVoList) {
                                String skuId = shoppingCartVo.getSkuId();
                                int newStock = shoppingCartVo.getSkuStock() - Integer.parseInt(shoppingCartVo.getCartNum());
                                ProductSku productSku = new ProductSku();
                                productSku.setSkuId(skuId);
                                productSku.setStock(newStock);
                                System.out.println(productSku);
                                int i1 = productSkuMapper.updateById(productSku);
                            }
                            //删除购物车
                            int i2 = shoppingCartMapper.deleteBatchIds(list);

                        }
                        //微信支付申请支付连接
                        WXPay wxPay = new WXPay(myPayConfig);
                        HashMap<String, String> data = new HashMap<>();
                        data.put("body", untitled);
                        data.put("out_trade_no", orders.getOrderId());
                        data.put("fee_type", "CNY");
                        data.put("total_fee", orders.getActualAmount() * 100 + "");
                        //data.put("total_fee", 1 + "");
                        data.put("trade_type", "NATIVE");
                        data.put("notify_url", "http://cn-jx-dx-1.msrx.online:8987/pay/callback");
                        Map<String, String> response = wxPay.unifiedOrder(data);
                        /*
                         * {"nonce_str":"lMpBNuSANn2yn2qO","code_url":"weixin://wxpay/bizpayurl?pr=5b4IRkjzz","appid":"wx632c8f211f8122c6","sign":"F8E2205386F30AB284F048420FA30F9E","trade_type":"NATIVE","return_msg":"OK","result_code":"SUCCESS","mch_id":"1497984412","return_code":"SUCCESS","prepay_id":"wx182156008768234faaa97eadf948df0000"}
                         *
                         * */
                        String resultCode = response.get("result_code");
                        if ("SUCCESS".equals(resultCode)) {
                            Map<String, String> orderInfo = new HashMap<>();
                            orderInfo.put("orderId", orders.getOrderId());
                            orderInfo.put("codeUrl", response.get("code_url"));
                            orderInfo.put("totalPrice", orders.getActualAmount() + "");
                            orderInfo.put("productName", untitled);
                            orderInfo.put("receiverName", orders.getReceiverName());
                            orderInfo.put("receiverMobile", orders.getReceiverMobile());
                            orderInfo.put("receiverAddress", orders.getReceiverAddress());
                            return ResultVo.success(orderInfo);
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                System.out.println("释放锁~~~");
                lockedList.stream().forEach(item -> {
                    lockMap.get(item).unlock();
                });
            }

            return ResultVo.fail(ResCode.ORDER_ERROR);
        }
    }

    @Override
    public int updateOrderStatus(String orderId, String status) throws Exception {
        Orders orders = new Orders();
        orders.setStatus(status);
        orders.setOrderId(orderId);
        orders.setPayTime(new Date());
        int i = ordersMapper.updateById(orders);
        return i;
    }

    @Override
    public ResultVo getOrderById(String orderId) throws Exception {
        Orders orders = ordersMapper.selectById(orderId);
        return ResultVo.success(orders.getStatus());
    }

    @Override
    @Transactional(isolation = Isolation.SERIALIZABLE)
    public void closeOrder(String orderId) throws Exception {
        synchronized (this) {
            //a.修改当前订单：status=6 已关闭 close_type=1 超时未支付
            Orders cancleOrder = new Orders();
            cancleOrder.setOrderId(orderId);
            cancleOrder.setStatus("6");
            cancleOrder.setCloseType(1);
            ordersMapper.updateById(cancleOrder);
            //b.还原库存:先根据当前订单编号查询商品快照（skuid buy_count）--->修改product_sku
            LambdaQueryWrapper<OrderItem> queryWrapper1 = new LambdaQueryWrapper<>();
            queryWrapper1.eq(OrderItem::getOrderId, orderId);
            List<OrderItem> orderItems = orderItemMapper.selectList(queryWrapper1);
            //还原库存
            orderItems.forEach(orderItem -> {
                ProductSku productSku = new ProductSku();
                productSku.setSkuId(orderItem.getSkuId());
                productSku.setStock(productSku.getStock() + orderItem.getBuyCounts());
                productSkuMapper.updateById(productSku);
            });
        }
    }

    @Override
    public ResultVo listOrders(String userId, String status, Integer pageNum, Integer pageSize) {
        //1.分页查询
        int start = (pageNum - 1) * pageSize;
        List<OrdersVo> ordersVos = ordersMapper.selectOrders(userId, status, start, pageSize);
        //2.查询总数
        LambdaQueryWrapper<Orders> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Orders::getUserId, userId);
        if (status != null && !"".equals(status)) {
            queryWrapper.eq(Orders::getStatus, status);
        }
        Long count = ordersMapper.selectCount(queryWrapper);
        //3.计算总页数
        long totalPage = count % pageSize == 0 ? count / pageSize : count / pageSize + 1;
        //4.封装数据
        PageHelperVo<OrdersVo> pageHelperVo = new PageHelperVo<>(count, totalPage, ordersVos);
        return ResultVo.success(pageHelperVo);
    }

    @Override
    @Transactional(isolation = Isolation.SERIALIZABLE)
    public void deleteOrderByOrderId(String orderId) throws Exception {
        ordersMapper.deleteById(orderId);
        LambdaQueryWrapper<OrderItem> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderItem::getOrderId, orderId);
        orderItemMapper.delete(queryWrapper);
    }
}
